﻿#region License
// MIT License
//
// Copyright(c) 2019-2025 ZhangYu
// https://gitee.com/zhangyu800/litebyte
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#region Intro
// Purpose: Reflection Optimize Performance
// Author: ZhangYu
// CreateDate: 2025-02-19
// LastModifiedDate: 2025-08-29
#endregion
namespace LiteByte.Reflection {

    using System.Reflection;
    using System.Runtime.InteropServices;

    /// <summary> 字段包装器接口 </summary>
    public interface IFieldWrapper {

        /// <summary> 获取字段的值 </summary>
        object GetValue(object instance);
        /// <summary> 设置字段的值 </summary>
        void SetValue(object instance, object value);

    }

    /// <summary> 字段反射包装器(用于对象字段的取值或赋值) </summary>
    public class FieldReflectionWrapper : IFieldWrapper {

        private FieldInfo field;

        public FieldReflectionWrapper(FieldInfo fieldInfo) {
            field = fieldInfo;
        }

        public object GetValue(object instance) {
            if (instance == null) return null;
            return field.GetValue(instance);
        }

        public void SetValue(object instance, object value) {
            if (instance != null) field.SetValue(instance, value);
        }

    }

    /// <summary> 字段指针包装器(用于对象字段的取值或赋值) </summary>
    public class FieldPointerWrapper : IFieldWrapper {

        private Type type;
        private TypeCode typeCode;
        private int offset;

        public FieldPointerWrapper(FieldInfo fieldInfo) {
            type = fieldInfo.FieldType;
            typeCode = Type.GetTypeCode(fieldInfo.FieldType);
            offset = GetFieldOffset(fieldInfo);
        }

        #pragma warning disable CS8500
        public unsafe object GetValue(object instance) {
            if (instance == null) return null;
            IntPtr ptr = *(IntPtr*)&instance + IntPtr.Size + offset;
            switch (typeCode) {
                case TypeCode.Boolean: return *(bool*)ptr;
                case TypeCode.Char: return *(char*)ptr;
                case TypeCode.SByte: return *(sbyte*)ptr;
                case TypeCode.Byte: return *(byte*)ptr;
                case TypeCode.Int16: return *(short*)ptr;
                case TypeCode.UInt16: return *(ushort*)ptr;
                case TypeCode.Int32: return *(int*)ptr;
                case TypeCode.UInt32: return *(uint*)ptr;
                case TypeCode.Int64: return *(long*)ptr;
                case TypeCode.UInt64: return *(ulong*)ptr;
                case TypeCode.Single: return *(float*)ptr;
                case TypeCode.Double: return *(double*)ptr;
                case TypeCode.Decimal: return *(decimal*)ptr;
                case TypeCode.DateTime: return *(DateTime*)ptr;
                case TypeCode.String: return *(string*)ptr;
                default:
                    if (type.IsValueType) {
                        return Marshal.PtrToStructure(ptr, type);
                    } else {
                        return *(object*)ptr;
                    }
            }
        }
        #pragma warning restore CS8500

        #pragma warning disable CS8500
        public unsafe void SetValue(object instance, object value) {
            if (instance == null) return;
            IntPtr ptr = *(IntPtr*)&instance + IntPtr.Size + offset;
            switch (typeCode) {
                case TypeCode.Boolean:
                    *(bool*)ptr = (bool)value;
                    break;
                case TypeCode.Char:
                    *(char*)ptr = (char)value;
                    break;
                case TypeCode.SByte:
                    *(sbyte*)ptr = (sbyte)value;
                    break;
                case TypeCode.Byte:
                    *(byte*)ptr = (byte)value;
                    break;
                case TypeCode.Int16:
                    *(short*)ptr = (short)value;
                    break;
                case TypeCode.UInt16:
                    *(ushort*)ptr = (ushort)value;
                    break;
                case TypeCode.Int32:
                    *(int*)ptr = (int)value;
                    break;
                case TypeCode.UInt32:
                    *(uint*)ptr = (uint)value;
                    break;
                case TypeCode.Int64:
                    *(long*)ptr = (long)value;
                    break;
                case TypeCode.UInt64:
                    *(ulong*)ptr = (ulong)value;
                    break;
                case TypeCode.Single:
                    *(float*)ptr = (float)value;
                    break;
                case TypeCode.Double:
                    *(double*)ptr = (double)value;
                    break;
                case TypeCode.Decimal:
                    *(decimal*)ptr = (decimal)value;
                    break;
                case TypeCode.DateTime:
                    *(DateTime*)ptr = (DateTime)value;
                    break;
                case TypeCode.String:
                    *(string*)ptr = (string)value;
                    break;
                default:
                    if (type.IsValueType) {
                        Marshal.StructureToPtr(value, ptr, true);
                    } else {
                        *(object*)ptr = value;
                    }
                    break;
            }
        }
        #pragma warning restore CS8500

        private unsafe static int GetFieldOffset(FieldInfo fieldInfo) {
            // Struct
            Type parentType = fieldInfo.ReflectedType;
            if (parentType.IsValueType) return (int)Marshal.OffsetOf(parentType, fieldInfo.Name);
            // Class
            IntPtr ptr = fieldInfo.FieldHandle.Value;
            ptr = ptr + 4 + IntPtr.Size;
            ushort length = *(ushort*)ptr;
            byte chunkSize = *(byte*)(ptr + 2);
            return length + (chunkSize << 16);
        }

    }

}
